package echo.future;

import echo.protocol.MessageProtocol;
import io.netty.util.CharsetUtil;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class DefaultFuture implements ResponseFuture {
    private static ConcurrentHashMap<Integer, DefaultFuture> FUTURES = new ConcurrentHashMap<>();
    private String res;
    private String req;
    private Integer id;
    private MessageProtocol messageProtocol;
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    private int timeout;

    public DefaultFuture(MessageProtocol messageProtocol) {
        id = messageProtocol.getReqId();
        this.messageProtocol = messageProtocol;
        timeout = 10000;
        FUTURES.put(id, this);
    }
    public DefaultFuture(MessageProtocol messageProtocol, int timeout) {
        id = messageProtocol.getReqId();
        this.messageProtocol = messageProtocol;
        this.timeout = timeout;
        FUTURES.put(id, this);
    }

    private static AtomicInteger i = new AtomicInteger();
    public static void received(MessageProtocol messageProtocol) {
        i.incrementAndGet();
        if (i.get() == 200) {
            System.out.println();
        }
        DefaultFuture future = FUTURES.remove(messageProtocol.getReqId());
        if (future == null) {
            throw new RuntimeException();
        }
        future.doReceive(messageProtocol);
    }

    private void doReceive(MessageProtocol messageProtocol) {
        lock.lock();

        try {
            res = new String(messageProtocol.getContent(), CharsetUtil.UTF_8);
            if (condition != null) {
                condition.signal();
            }
        } finally {
            lock.unlock();
        }
    }


    @Override
    public Object get() throws InterruptedException {
        lock.lock();
        if (!isDone()) {
            while (!isDone()) {
                try {
                    condition.await(timeout, TimeUnit.MILLISECONDS);
//                    System.out.println(FUTURES);
                    break;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
            }
        }
        return res;

    }

    @Override
    public Object get(int timeOut) {
        return null;
    }

    @Override
    public void setCallback(ResponseCallback responseCallback) {

    }

    @Override
    public boolean isDone() {
        return res != null;
    }

    private static class RemotingInvocationScan implements Runnable {
        @Override
        public void run() {
            for (; ; ) {
                for (DefaultFuture future : FUTURES.values()) {
                    if (future == null || future.isDone()) {
                        continue;
                    }
//                    DefaultFuture.receved();

                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public String getReq() {
        return req;
    }

    public void setReq(String req) {
        this.req = req;
    }

    @Override
    public String toString() {
        return "DefaultFuture{" +
                "res='" + res + '\'' +
                ", req='" + req + '\'' +
                '}';
    }
}
